package club.jdiy.utils;

import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * 数组工具类.
 *
 * @author ziquee(子秋) QQ号:39886616 主页: http://www.jdiy.club
 * @version 20200517
 */
@SuppressWarnings("ALL")
public final class ArrayUtils {
    private ArrayUtils() {
    }

    /**
     * 求并集
     */
    public static <T> Set<T> merge(T[] a, T[] b) {
        // 将数组转换为set集合
        return merge(Arrays.asList(a), Arrays.asList(b));
    }

    /**
     * 求并集
     */
    public static <T> Set<T> merge(Collection<T> a, Collection<T> b) {
        // 将数组转换为set集合
        Set<T> set1 = new HashSet<>(a);
        Set<T> set2 = new HashSet<>(b);
        set1.addAll(set2);
        return set1;
    }

    /**
     * 求交集
     */
    public static <T> Set<T> overlap(T[] a, T[] b) {
        return overlap(Arrays.asList(a), Arrays.asList(b));
    }

    /**
     * 求交集
     */
    public static <T> Set<T> overlap(Collection<T> a, Collection<T> b) {
        // 将较长的数组转换为set
        Set<T> set = new HashSet<>(a.size() > b.size() ? a : b);
        // 遍历较短的数组，实现最少循环
        return (a.size() > b.size() ? b : a).stream().filter(set::contains).collect(Collectors.toSet());
    }

    /**
     * 求不同（剔除相同的数据，剩下的合并）
     */
    public static <T> Set<T> difference(T[] a, T[] b) {
        return difference(Arrays.asList(a), Arrays.asList(b));
    }

    /**
     * 求不同（剔除相同的数据，剩下的合并）
     */
    public static <T> Set<T> difference(Collection<T> a, Collection<T> b) {
        // 将较长的数组转换为set
        Set<T> set = new HashSet<>(a.size() > b.size() ? a : b);
        // 遍历较短的数组，实现最少循环
        // 如果集合里有相同的就删掉，如果没有就将值添加到集合
        (a.size() > b.size() ? b : a).stream().forEach(i -> {
            if (set.contains(i)) {
                set.remove(i);
            } else {
                set.add(i);
            }
        });
        return set;
    }

    /**
     * 求差集(a-b)
     */
    public static <T> Set<T> subtract(T[] a, T[] b) {
        return subtract(Arrays.asList(a), Arrays.asList(b));
    }

    /**
     * 求差集(a-b)
     */
    public static <T> Set<T> subtract(Collection<T> a, Collection<T> b) {
        Set<T> set = new LinkedHashSet<>(a);
        b.stream().forEach(i -> {
            if (set.contains(i)) set.remove(i);
        });
        return set;
    }


    /**
     * 将字符串数组元素按指定的字符串分隔符连成一个新的字符串。
     *
     * @param sa        要连接的字符串数组.
     * @param separator 连接字符串. 如果此字符串为空(null)，则使用逗号加一个空格(, )进行连接。
     * @return 返回arr的每个下标元素按joinStr连接成的新的字符串. 如果数组arr为空(null),则返回结果也将为null.
     */
    public static String join(String[] sa, String separator) {
        if (sa == null) return null;
        if (sa.length < 1) return "";
        return Arrays.stream(sa).map(s -> separator + s).collect(Collectors.joining()).substring(separator.length());
    }

    /**
     * 将集合的每一个元素按toString()串化后，再按指定的字符串分隔符连成一个新的字符串。
     *
     * @param sa        要join连接的Collection集合.
     * @param separator 连接分隔字符串. 如果此字符串为空(null)，则使用逗号加一个空格(, )进行连接。
     * @return 返回Collection的每个下标元素按joinStr连接成的新的字符串. 如果Collection为空(null),则返回结果也将为null.
     */
    public static <T> String join(Collection<T> sa, String separator) {
        return join(sa, separator, Objects::toString);
    }

    /**
     * 将集合的每一个元素按指定的字符串分隔符连成一个字符串. <br/><br/>
     * <strong>示例：</strong> (假设要将所有用户的id主键，转换成：id1|id2|id3 这样的由竖线分隔的形式)<br/>
     * <pre>
     * List&lt;User&gt; userList=userService.findAll();
     * String ret = ArrayUtils.join(userList,"|", u -> u.getId());
     * </pre>
     *
     * @param sa        要join连接的Collection集合.
     * @param separator 连接分隔字符串. 如果此字符串为空(null)，则使用逗号加一个空格(, )进行连接。
     * @param fn        提供一个Function，将集合中的单个元素串化.
     * @return 返回Collection的每个下标元素按separator连接成的新的字符串. 如果Collection为空(null),则返回结果也将为null.
     */
    public static <T> String join(Collection<T> sa, String separator, Function<T, String> fn) {
        final String sp = separator == null ? ", " : separator;
        if (sa == null) return null;
        if (sa.isEmpty()) return "";
        return sa.stream().map(s -> sp + fn.apply(s)).collect(Collectors.joining()).substring(sp.length());
    }


    /**
     * 将字符串按指定的分隔符分割成为一个数组.   <br />
     * 与String.split(String s)、StringTokenizer不同的是，此方法将比它们更加高效快速.
     * 在需要将字符串split转换为数组时，应该优先使用此方法.
     *
     * @param str 要转换的字符串.
     * @param sp  分隔字符串.
     * @return 转换后的String数组.
     * @since JDiy-1.6 及以上版本新增的方法.
     */
    public static String[] split(String str, String sp) {
        List<String> arrayList = new ArrayList<String>();
        int index = 0, offset = 0, len = sp.length();
        while ((index = str.indexOf(sp, index + len)) != -1) {
            arrayList.add(str.substring(offset, index));
            offset = index + len;
        }
        if (offset < str.length()) arrayList.add(str.substring(offset));
        return arrayList.toArray(new String[arrayList.size()]);
    }


    public static Integer[] toIntArray(String str, String split) {
        return Arrays.stream(str.split(split)).filter(s -> !"".equals(s)).map(Integer::parseInt).toArray(Integer[]::new);
    }

    public static Long[] toLongArray(String str, String split) {
        return Arrays.stream(str.split(split)).filter(s -> !"".equals(s)).map(Long::parseLong).toArray(Long[]::new);
    }

}
